//! # 使用
//! ```
//!         use algorithms_fourth::io::writer::BinaryWriter;
//!         let mut writer = BinaryWriter::new(120);
//!         writer.writer_bool(true);
//!         assert_eq!(writer.len(), 1);
//!         writer.writer_bool(false);
//!         writer.writer_u8((1 << 2) + (1 << 7));
//!         assert_eq!(writer.len(), 2 + 8);
//!         writer.write_u64(1 << 2);
//!         assert_eq!(writer.len(), 2 + 8 + 64);
//!         assert!(writer.need_flush());
//!        println!("{:?}", writer.flush());
//!         assert!(!writer.need_flush());
//!         // println!("{:?}", writer.data);
//!         writer.writer_bool(true);
//!         assert_eq!(writer.close(),vec![1<<(8-3)]);
//!
//! ```

// use std::mem::size_of;
pub struct BinaryWriter {
    data: Vec<bool>,
}
// const  U:usize = size_of::<usize>() * 8;
impl BinaryWriter {
    pub fn new(cap: usize) -> Self {
        BinaryWriter {
            data: Vec::with_capacity(cap),
        }
    }
    pub fn writer_bool(&mut self, val: bool) {
        self.data.push(val);
    }
    pub fn writer_u8(&mut self, val: u8) {
        for i in (0..8).rev() {
            let t = 1 << i;
            self.data.push(t & val == t);
        }
    }
    pub fn write_u32(&mut self, val: u32) {
        let bit = 32;
        for i in (0..bit).rev() {
            let t = 1 << i;
            self.data.push(t & val == t);
        }
    }

    pub fn write(&mut self, bit: usize, val: usize) {
        let i = self.data.len();
        for i in (0..bit).rev() {
            let t = 1 << i;
            self.data.push(t & val == t);
        }
        debug_assert_ne!(self.data.len(), i);
    }
    pub fn write_u64(&mut self, val: u64) {
        for i in (0..64).rev() {
            let t = 1 << i;
            self.data.push(t & val == t);
        }
    }
    pub fn len(&self) -> usize {
        self.data.len()
    }
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
    pub fn need_flush(&self) -> bool {
        self.data.len() > 8 * 4
    }
    pub fn flush(&mut self) -> Vec<u8> {
        let mut iter = self.data.chunks_exact(8);
        let mut ans = Vec::with_capacity(iter.len());
        for it in iter.by_ref() {
            let item = it
                .iter()
                .map(|&e| if e { 1 } else { 0 })
                .reduce(|acc, e| (acc << 1) + e)
                .unwrap() as u8;
            ans.push(item);
        }
        let mut data = Vec::with_capacity(iter.remainder().len());
        for &it in iter.remainder() {
            data.push(it);
        }
        self.data = data;
        ans
    }
    pub fn close(mut self) -> Vec<u8> {
        let mut ans = self.flush();
        if !self.is_empty() {
            let s = 8 - self.len();
            let mut a = self
                .data
                .into_iter()
                .map(|f| if f { 1 } else { 0 })
                .reduce(|acc, e| (acc << 1) + e)
                .unwrap() as u8;
            a <<= s;
            ans.push(a);
        }
        ans
    }

    pub fn to_string(&self) -> String {
        let mut res = String::with_capacity(self.len());
        self.data.iter().for_each(|&f| {
            let item = if f { '1' } else { '0' };
            res.push(item)
        });
        res
    }
}
#[cfg(test)]
mod test {
    use super::BinaryWriter;

    #[test]
    fn test() {
        let mut writer = BinaryWriter::new(120);
        writer.writer_bool(true);
        assert_eq!(writer.data.len(), 1);
        assert_eq!(writer.data, vec![true]);
        writer.writer_bool(false);
        assert_eq!(writer.data, vec![true, false]);
        writer.writer_u8((1 << 2) + (1 << 7));
        assert_eq!(writer.len(), 2 + 8);
        assert_eq!(
            writer.data,
            vec![true, false, true, false, false, false, false, true, false, false]
        );
        writer.write_u64(1 << 2);
        assert_eq!(writer.len(), 2 + 8 + 64);
        assert!(!writer.data[2 + 8]);
        assert!(writer.data[2 + 8 + 64 - 3]);
        assert!(writer.need_flush());
        println!("{:?}", writer.flush());
        assert!(!writer.need_flush());
        // println!("{:?}", writer.data);
        writer.writer_bool(true);
        assert_eq!(writer.close(), vec![1 << (8 - 3)]);
    }
}
